MiniBatGUI {
	
	/*
	MiniBatGUI.new("127.0.0.1");
	(
	Speech.init(1);
	Speech.channels[0].voice_(3);
	Speech.channels[0].pitchMod_(0);
	Speech.setSpeechRate(0, 175);
	Speech.channels[0].speak("Thank you for coming. We are Lag, a theoretically transcontinental network laptop quartet. 	Because of the lack of internet connectivity, today we are perfoming as a duo. We hope you enjoy our music or at least 	don't hate it alot. Our first piece is called Mini Bat Generator versus Monster Generator. Its about bats and monsters 	and stuff. It would help if you visualized hyperbolic digital violence during the music. ")
	)
	*/
		
	var batGrad,monsterGrad,window,batGen,monsterGen,batVolume,monsterVolume,batSynth,oozeGrad,trigLight;
	var monsterSynth,batToggle,monsterToggle,responder,addr,oozeSynth,oozeToggle,oozeGen,oozeVolume,trigRoutine;
	
	*new { arg ip="127.0.0.1";
		^super.new.init(ip);
	}
	
	init { arg ip="127.0.0.1";
		this.compileSynths;
		addr = NetAddr(ip,22244);
		responder = OSCresponder(nil,'/miniBat',{
			|t,r,msg|
			//msg.postln;
			case
			{ msg[1]=='/batGen' } { this.batGen; trigLight.doAction; }
			{ msg[1]=='/oozeGen' } { this.oozeGen; }
			{ msg[1]=='/monsterGen' } { this.monsterGen; }
			{ msg[1]=='/batAmp' } { this.batAmp(msg[2]); }
			{ msg[1]=='/oozeAmp' } { this.oozeAmp(msg[2]); }
			{ msg[1]=='/monsterAmp' } { this.monsterAmp(msg[2]); };
			
		}).add;
		batToggle = 0;
		oozeToggle = 0;
		monsterToggle = 0;
		batSynth = Array.newClear(2);
		oozeSynth = Array.newClear(2);
		monsterSynth = Array.newClear(2);
		this.makeGUI();
	}
	
	makeGUI { 		
		window = SCWindow.new("Mini-bat Generator vs. Ooze Generator vs. Monster Generator",Rect(300,300,775,220)).front;
		trigLight = SmoothButton.new(window,Rect(350,148,65,65))
			.states_([
				["",Color.black,Color.new255(0,0,0,0)]
			])
			.action_({ |v|
				if(trigRoutine != nil, { trigRoutine.stop });
				trigRoutine = Routine.new({
					10.do{
						|i|
						v.states_([
								["",Color.black,Color.new255(255,255,255,255*((10-i).abs/10))]
							]);
						
						0.0125.wait;
						
					}	 
				}).play(AppClock);
			})
			.canFocus_(false);	
		
		window.view.decorator = FlowLayout(window.view.bounds);
		window.background_(Color.new255(210,230,255));
		window.view.background_(Gradient.new(Color.rand,Color.rand,[\h,\v].choose));
		batGrad = Gradient.new(Color.rand,Color.rand,[\h,\v].choose);
		oozeGrad = Gradient.new(Color.rand,Color.rand,[\h,\v].choose);
		monsterGrad = Gradient.new(Color.rand,Color.rand,[\h,\v].choose);
		
		// Key Actions
		window.view.keyDownAction_({
			|view,char,modifiers,unicode,keycode|
			char.asAscii.postln;
			char.asAscii.class.postln;
			unicode.postln;
			keycode.postln;
			
			switch(keycode,
				18,		{ addr.sendMsg("/miniBat","/batGen"); this.batGen; trigLight.doAction; },
				19,		{ addr.sendMsg("/miniBat","/oozeGen"); this.oozeGen; },
				20,		{ addr.sendMsg("/miniBat","/monsterGen"); this.monsterGen; }
			);
		});
		
		batGen = SmoothButton.new(window,Rect(0,0,250,100))
			.canFocus_(false)
			.states_
			([
				[ 
					"Generate Mini-bat",
					Color.black,
					batGrad
				]
			])
			.action_({ addr.sendMsg("/miniBat","/batGen"); this.batGen; trigLight.doAction; })
			.radius_(40);
			
		oozeGen = SmoothButton.new(window,Rect(0,0,250,100))
			.canFocus_(false)
			.states_
			([
				[ 
					"Generate Ooze",
					Color.black,
					oozeGrad
				]
			])
			.action_({ addr.sendMsg("/miniBat","/oozeGen"); this.oozeGen; })
			.radius_(40);	
			
		monsterGen = SmoothButton.new(window,Rect(0,0,250,100))
			.canFocus_(false)
			.states_
			([
				[ 
					"Generate Monster",
					Color.black,
					monsterGrad
				]
			])
			.action_({ addr.sendMsg("/miniBat","/monsterGen"); this.monsterGen; })
			.radius_(40);
			
		batVolume = SmoothSlider.new(window,Rect(0,0,250,30))
			.knobSize_(0.075)
			.knobColor_(Color.rand)
			.canFocus_(false)
			.background_(Color.rand)
			.value_(0.5)
			.action_({ |v| addr.sendMsg("/miniBat","/batAmp",v.value); this.batAmp(v.value); });
			
		oozeVolume = SmoothSlider.new(window,Rect(0,0,250,30))
			.knobSize_(0.075)
			.knobColor_(Color.rand)
			.canFocus_(false)
			.background_(Color.rand)
			.value_(0.5)
			.action_({ |v| addr.sendMsg("/miniBat","/oozeAmp",v.value); this.oozeAmp(v.value); });
			
		monsterVolume = SmoothSlider.new(window,Rect(0,0,250,30))
			.knobSize_(0.075)
			.knobColor_(Color.rand)
			.canFocus_(false)
			.background_(Color.rand)
			.value_(0.5)
			.action_({ |v| addr.sendMsg("/miniBat","/monsterAmp",v.value); this.monsterAmp(v.value); });
			
		window.refresh;
		window.front;

	}
	
	batGen {
		
		if(batSynth != nil, 
			{ 
				batSynth[batToggle].set(\gate,0); 
				batToggle = (1-batToggle).abs;
				batSynth[batToggle] = Synth([\MiniBatGeneratorFFT,\MiniBatGenerator2].choose,[\out,0]);
			},{
				batSynth[batToggle] = Synth([\MiniBatGeneratorFFT,\MiniBatGenerator2].choose,[\out,0]);
				batToggle = (1-batToggle).abs;
			});
		
		{
			batGrad = Gradient.new(Color.rand,Color.rand,[\h,\v].choose);
			batGen.states_
				([
					[ 
						"Generate Mini-bat",
						Color.black,
						batGrad
					]
				]);
			batVolume.background_(Color.rand);
			batVolume.hilightColor_(Color.rand);
			batVolume.value_(0.5).knobColor_(Color.rand);
			window.view.background_(Gradient.new(Color.rand,Color.rand,[\h,\v].choose));
		}.defer;
	}
	
	batAmp { arg volume;
		batSynth[batToggle].set(\amp,volume);
	}
	
	oozeGen {
		
		if(oozeSynth != nil, 
			{ 
				oozeSynth[oozeToggle].set(\gate,0); 
				oozeToggle = (1-oozeToggle).abs;
				oozeSynth[oozeToggle] = Synth(\OozeGenerator,[\out,0]);
			},{
				oozeSynth[oozeToggle] = Synth(\OozeGenerator,[\out,0]);
				batToggle = (1-oozeToggle).abs;
			});
		
		{
			oozeGrad = Gradient.new(Color.rand,Color.rand,[\h,\v].choose);
			oozeGen.states_
				([
					[ 
						"Generate Ooze",
						Color.black,
						oozeGrad
					]
				]);
			oozeVolume.background_(Color.rand);
			oozeVolume.hilightColor_(Color.rand);
			oozeVolume.value_(0.5).knobColor_(Color.rand);
			window.view.background_(Gradient.new(Color.rand,Color.rand,[\h,\v].choose));
		}.defer;
	}
	
	oozeAmp { arg volume;
		oozeSynth[oozeToggle].set(\amp,volume);
	}
	
	
	monsterGen {

		if(monsterSynth != nil, 
			{ 
				monsterSynth[monsterToggle].set(\gate,0); 
				monsterToggle = (1-monsterToggle).abs;
				monsterSynth[monsterToggle] = Synth(\MonsterGenerator,[\out,1]);
			},{
				monsterSynth[monsterToggle] = Synth(\MonsterGenerator,[\out,1]);
				monsterToggle = (1-monsterToggle).abs;
			});
			
		{
			monsterGrad = Gradient.new(Color.rand,Color.rand,[\h,\v].choose);
			monsterGen.states_
				([
					[ 
						"Generate Monster",
						Color.black,
						monsterGrad
					]
				]);
			monsterVolume.background_(Color.rand);
			monsterVolume.hilightColor_(Color.rand);
			monsterVolume.value_(0.5).knobColor_(Color.rand);
			window.view.background_(Gradient.new(Color.rand,Color.rand,[\h,\v].choose));
		}.defer;
	}
	
	monsterAmp { arg volume;
		monsterSynth[monsterToggle].set(\amp,volume);
	}
	
	compileSynths {
		
		SynthDef.new(\OozeGenerator,{
			|amp=0.5,out=0,gate=1|
			var pulse,env,signal,feed,delay,mod,feedSignal,freq1,sequence,blip,blip2,pw,buffer,rdPos,henon;
			var pulse2,env2,perc,form,formFreq,noise,noiseEnv,noiseGate,verb,phasorWr,phasorRd,bufRd;
			feed = LocalIn.ar(2);
			env = EnvGen.ar(Env.asr(0.0001,1.0,0.1,4),gate:gate,doneAction:2);
			
			sequence = Duty.kr(
				Dseq(Array.fill(5,{ ExpRand(0.01,1.5) }),inf),
				0,
				Dseq(Array.fill(5,{ Rand(0.0,1.0) }),inf),
				doneAction:0);
				
			blip = Blip.ar(sequence.linexp(0,1,20,1000)*LFSaw.ar(ExpRand(0.5,20),0,Rand(0,1),Rand(0,1)),ExpRand(1,100),0.3);
			blip2 = Blip.ar(ExpRand(5,160),sequence.linlin(0,1,1,500),0.3);
			blip2 = BMoog.ar(blip2,Lag.kr(sequence.linexp(0,1,160,20000),ExpRand(0.01,1.0)),Rand(0,0.98),Rand(0,3),Rand(0,1));
			
			mod = Select.ar(
				Rand(0,2),
				[
					SinOsc.ar(ExpRand(0.25,20),Rand(0.1,0.9),Rand(0,1),Rand(0,1)),
					Pulse.ar(ExpRand(0.25,20),Rand(0.1,0.9),Rand(0,1),Rand(0,1)),
					LFCub.ar(ExpRand(0.25,20),Rand(0.1,0.9),Rand(0,1),Rand(0,1))
				]
			);
			mod = Lag.ar(mod,ExpRand(0.01,1))+feed[0];
			mod = BufDelayC.ar(LocalBuf(44100),mod,Rand(0.05,1),1,mod);
			freq1 = (ExpRand(20,ExpRand(30,2000))*mod)%ExpRand(100,2000);
			pw = Select.ar(
				Rand(0,3),
				[
					SinOsc.ar(ExpRand(0.5,20),0,0.5,0.5),
					Saw.ar(ExpRand(0.5,20),0.5,0.5),
					Pulse.ar(ExpRand(0.5,20),Rand(0.1,0.9),0.5,0.5),
					LFTri.ar(ExpRand(0.5,20),Rand(0.1,0.9),0.5,0.5),
				]);
			pulse = SinOsc.ar(freq1*pw,ExpRand(1,8pi),0.2);
			pulse = pulse+SinOsc.ar(freq1*0.5*pw,ExpRand(1,8pi),0.2);
			pulse = BMoog.ar(pulse,ExpRand(30,20000),Rand(0,0.95),Rand(0,3),Rand(0,1));
			pulse2 = pulse+(feed[1]*Rand(0.6,0.95));
			pulse2 = Select.ar(
				Rand(0,2),
				[
					OnePole.ar(pulse2,Rand(-0.99,0.99)),
					OneZero.ar(pulse2,Rand(-0.5,0.5)),
					LPZ1.ar(pulse2)
				]);
			pulse2 = Select.ar(
				Rand(0,2),
				[
					OnePole.ar(pulse2,Rand(-0.99,0.99)),
					OneZero.ar(pulse2,Rand(-0.5,0.5)),
					LPZ1.ar(pulse2)
				]);
				
			pulse = Select.ar(
				Rand(0,1),
				[
					pulse,
					pulse2
				]);	
				
			env2 = EnvGen.ar(
				Env.new(
					[0,1,Rand(0.3,1),0],
					[ExpRand(0.0001,1),Rand(0.01,0.25),ExpRand(0.125,1)],
					Rand(-8,8)),
				gate: Gate.ar(Impulse.ar(ExpRand(0.5,20)),Pulse.ar(ExpRand(0.5,20),Rand(0.1,0.9),0.5,0.5)),
				doneAction:0);
			
			perc = Select.ar(
				Rand(0,2),
				[
					Pulse.ar(ExpRand(20,80),env2*0.5,env2*0.3),
					SinOsc.ar(ExpRand(20,1000),env2*ExpRand(1,8pi),env2*0.3),
					WhiteNoise.ar(env2*0.3)
				]);
			
			perc = Select.ar(
				Rand(0,2),
				[
					RLPF.ar(perc,ExpRand(80,1000)*env2,Rand(0.05,1)),
					RHPF.ar(perc,ExpRand(80,1000)*env2,Rand(0.05,0.5)),
					BMoog.ar(perc,ExpRand(30,1000)*env2,Rand(0,0.95),Rand(0,3),Rand(0,1))
				]);
				
			formFreq = Lag.kr(sequence.linexp(0,1,20,1000),ExpRand(0.001,1));
				
			form = Formant.ar(
				formFreq,
				ExpRand(5,500)*env2,
				formFreq+ExpRand(1,160));
				
			form = Decay.ar(K2A.ar(HPZ1.kr(sequence)),Rand(0.25,2),form*0.2);
			
			noise = Select.ar(
				Rand(0,5),
				[
					WhiteNoise.ar(1),
					PinkNoise.ar(1),
					GrayNoise.ar(1),
					LFNoise0.ar(ExpRand(20,80)),
					Dust2.ar(ExpRand(5,80)),
					Dust.ar(ExpRand(1,20)),
				]);
				
			noiseGate = Gate.ar(Impulse.ar(ExpRand(1,40)),Pulse.ar(ExpRand(0.5,20),Rand(0.1,0.9),0.5,0.5));
			
			noiseEnv = EnvGen.ar(
				Env.new(
					[0,1,Rand(0.3,1),Rand(0.3,1),0],
					[ExpRand(0.0001,0.1),Rand(0.01,0.125),0.125,ExpRand(0.125,0.25)],
					Rand(-8,8)),
				gate: noiseGate,
				doneAction:0);
				
			noise = Select.ar(
				Rand(0,2),
				[
					RLPF.ar(noise*noiseEnv,(ExpRand(80,1000)+TExpRand.ar(1,ExpRand(20,200),CoinGate.ar(Rand(0.1,1),noiseGate)))*noiseEnv,TRand.kr(0.0025,0.01,noiseGate)),
					RHPF.ar(noise*noiseEnv,(ExpRand(80,1000)+TExpRand.ar(1,ExpRand(20,200),CoinGate.ar(Rand(0.1,1),noiseGate)))*noiseEnv,TRand.kr(0.0025,0.01,noiseGate)),
					BMoog.ar(
						noise*noiseEnv,
						(ExpRand(80,1000)+TExpRand.ar(1,ExpRand(20,200),CoinGate.ar(Rand(0.1,1),noiseGate)))*noiseEnv,
						TRand.kr(0.95,0.999,noiseGate),TRand.kr(0,3,noiseGate),Rand(0,1))
				]);
			
			noise = (noise*ExpRand(10,ExpRand(20,50))).softclip*0.2;
				
			signal = Select.ar(
				Rand(0,5),
				[
					pulse,
					blip,
					blip2,
					LeakDC.ar(SanityCheck.ar(perc).softclip),
					form,
					noise
				]);
				
			buffer = LocalBuf(SampleRate.ir);
			phasorWr = Phasor.ar(0,1,SampleRate.ir,0);
			BufWr.ar(signal,buffer,phasorWr,1);
			rdPos = Rand(0,SampleRate.ir)*sequence;
			henon = Latch.ar(SinOsc.ar(ExpRand(0.25,15),SinOsc.ar(ExpRand(20,2000),0,0.5,0.5)*ExpRand(1,8pi),Rand(0,1),Rand(0,1)),Impulse.kr(ExpRand(0.5,15)));
			phasorRd = Phasor.ar(
				Impulse.ar(Lag.kr(ExpRand(5,160)*sequence,ExpRand(0.001,1.0)))+HPZ1.kr(sequence),
				ExpRand(1,ExpRand(5,300))*henon,
				rdPos,
				rdPos+Rand(-5000,5000));
			bufRd = LeakDC.ar(SanityCheck.ar(BufRd.ar(1,buffer,phasorRd,1,0)))*0.5;
			
			signal = TWChoose.ar(
				Impulse.ar(0),
				[
					signal,
					bufRd
				],[0.6,0.5]);
				
			verb = Limiter.ar(GVerb.ar(	
						Mix.new(signal*0.5),
						ExpRand(0.1,80),
						ExpRand(0.01,10),
						Rand(0,1),
						Rand(0,1),
						15,
						Rand(-30,-6),
						Rand(-30,-9),
						Rand(-30,-9)
						)[0]*0.12,0.2,0.05);
				
			signal = TWChoose.ar(
				Impulse.ar(0),
				[
					verb,
					signal
				],
				[0.3,0.7]);
								
			//signal = Pan2.ar(Compander.ar(signal*3,signal*3,0.3,1,0.5,0.01,0.01)*env,0);
			signal = Pan2.ar(Limiter.ar(SanityCheck.ar(signal)*6,0.4,0.01).softclip*env,0);
			Out.ar(out,signal*amp);
			feedSignal = (mod*Rand(0,1));
			feedSignal = Select.ar(
				Rand(0,7),
				[
					feedSignal.fold2(1.0),
					feedSignal.wrap2(1.0),
					feedSignal%Rand(0.1,1),
					feedSignal.ring2(1),
					feedSignal.clip2(Rand(0,1)),
					feedSignal.thresh(Rand(0,1)),
					feedSignal.sqrt,
					feedSignal.neg
				]
			);
			LocalOut.ar([feedSignal*LFSaw.ar(Rand(0.1,20),0,0.5,0.5),BufDelayC.ar(LocalBuf(44100*0.5),pulse2,Rand(0.0001,0.5))]);
			}).store;
		
				
		SynthDef.new(\MonsterGenerator,{
			|amp=0.5,out=0,gate=1|
			var modulators,spring,ball,line,trigEnv,modPulse,sine,feed,lfTri,pitch,pitchFreq,pitchOn;
			var pulse,formant,formFreq,osc,buffer,gray,dust,oscillators,env,signal,gendy,blip,pluck;
			var verb,delay,ringz,convolve,filter,integrator,twoZero,fos,effects,decimate,freqShift,filter2;
			var feedEffects,sineOsc,pulseGaps,formlet,klank,ringMod,divider,buffer2;
			env = EnvGen.ar(Env.asr(0.0001,1.0,0.1,4),gate:gate,doneAction:2);
			feed = LocalIn.ar(1);
			buffer = LocalBuf(44100);
			buffer2 = LocalBuf(512);
			// Modulators;
			trigEnv = EnvGen.ar(Env.new([ExpRand(0.0001,1.0),Rand(0.1,1.0)],[Rand(0.0001,1.0)+feed+1],-4),gate:Impulse.ar(ExpRand(1.0,20.0)),doneAction:0);
			line = Line.ar(Rand(0.0,0.5),Rand(0.1,0.5),ExpRand(0.0001,5.0))+Line.ar(Rand(0.0,0.5),Rand(0.1,0.5),ExpRand(0.0001,5.0));
			spring = Spring.ar(feed,Rand(1.0,200.0),Rand(0.001,0.1));
			ball = Ball.ar(feed,Rand(1.0,200.0),Rand(0.1,1.0),Rand(0.001,0.1));
			BufWr.ar(spring,buffer2,Phasor.ar(0,Rand(0.5,2.0),512),1);
			modPulse = Pulse.ar(ExpRand(0.5,20.0),feed,Rand(0.1,0.9),0.5,0.5);
			sine = SinOsc.ar(ExpRand(0.5,20.0),feed,0.25,0.25);
			lfTri = LFTri.ar(ExpRand(1.0,20.0),(feed+1*4),0.5,0.5);
			pitch = K2A.ar(Pitch.kr(feed+SinOsc.ar(ExpRand(1,2000.0))).linlin(20.0,20000.0,0.0,1.0));
			pitchFreq = pitch[0];
			pitchOn = pitch[1];
			modulators = Select.ar(
				IRand(0,8),
				[
					trigEnv,
					line,
					spring,
					ball,
					modPulse,
					sine,
					lfTri,
					pitchFreq,
					pitchOn
				]);
				
			
			modulators = Select.ar(
				IRand(0,6),
				[
					modulators,
					modulators,
					Latch.ar(modulators,Impulse.ar(ExpRand(1.0,15.0))),
					Decay.ar(modulators,Rand(0.5,5.0),Trig.kr(feed)+Impulse.ar(Rand(1.0,5.0))),
					Lag.ar(modulators,Rand(0.01,0.25)),
					BufDelayC.ar(LocalBuf(44100*0.25),modulators,Rand(0,0.25),1,modulators)*0.5,
					BufAllpassC.ar(LocalBuf(44100*0.1),modulators,Rand(0.01,0.1),Rand(0.0001,0.5),1,modulators)*0.5
				]);
					
			
			// Oscillators
			pulse = Pulse.ar(ExpRand(20.0,1000.0) + (feed * ExpRand(20.0,2000.0)),modulators.max(0.1).min(0.9));
			formFreq = ExpRand(20.0,10000.0);
			formant = Formant.ar(formFreq ring2: modulators,ExpRand(20.0,10000.0),formFreq * Rand(1.0,2.0) ring2: modulators) + feed;
			gendy = Gendy1.ar(Rand(0,6),Rand(0.1,1.0),modulators,modulators,1.0,ExpRand(20.0,2000.0) ring1: feed,Rand(0.1,1.0),Rand(0.1,1.0),12,12);
			gendy = SinOsc.ar((gendy*ExpRand(20.0,3000.0))+ExpRand(20.0,80.0));
			blip = Blip.ar(ExpRand(20.0,40.0) + (modulators.linexp(0.0,1.0,2.0,20.0)),Rand(1,10.0) + (modulators*10)) ring2: feed;
			osc = Osc.ar(buffer2,ExpRand(20.0,100.0) + modulators ring1: feed,modulators*2*pi)+(Impulse.ar(Rand(1.0,15.0)) ring2: feed);
			gray = Decay.ar(SinOsc.ar(Rand(20.0,100.0))+feed,Rand(0.2,2.0), modulators+(Pulse.ar(Rand(0.5,10.0),Rand(0.1,0.9))));
			dust = Decay.ar(Dust.ar(ExpRand(1.0,20.0)),Rand(0.2,1.0),modulators ring1: feed);
			pluck = Pluck.ar(Pulse.ar(ExpRand(20.0,1000.0),Rand(0.1,0.9),0.5),Impulse.ar(Rand(1.0,15.0))*modulators,0.25,ExpRand(20,1000.0).reciprocal,Rand(0.1,0.5))+feed;
			sineOsc = SinOsc.ar(ExpRand(20.0,500.0)+(modulators*ExpRand(1.0,500.0))) + feed;
			pulseGaps = Pulse.ar(ExpRand(1.0,20.0),Rand(0.1,0.9),modulators) + Pulse.ar(ExpRand(1.0,20.0),Rand(0.1,0.9),feed) + feed;
			formlet = Formlet.ar(modulators + Impulse.ar(ExpRand(1.0,40.0)),ExpRand(20.0,2000.0),ExpRand(0.0001,0.5) ring1: modulators,Rand(0.1,1.0)) + feed;
			
			oscillators = Select.ar(
				IRand(0,10),
				[
					pulse,
					formant,
					gendy,
					blip,
					osc,
					gray,
					dust,
					pluck,
					sineOsc,
					pulseGaps,
					formlet
				]);
				
			// Effects
			verb = FreeVerb.ar(oscillators,Rand(0.5,0.95),Rand(0.0,1.0),Rand(0.0,1.0));
			delay = BufDelayC.ar(buffer,RLPF.ar(oscillators,ExpRand(500.0,5000.0),Rand(0.5,0.1)),Rand(0.1,1.0),1,oscillators);
			ringz = Ringz.ar(oscillators,ExpRand(200.0,3000.0),ExpRand(0.5,5.0));
			filter = BMoog.ar(oscillators,ExpRand(200.0,3000.0),0.95,Rand(0,3),Rand(0.0,1.0));
			filter2 = BMoog.ar(oscillators,(Amplitude.kr((oscillators*2).clip2(1.0)+Impulse.ar(0.25),Rand(0.1,0.5),Rand(0.5,5.0))*ExpRand(400.0,3000.0)).max(50),0.95,0);
			convolve = Convolution2.ar(oscillators,buffer2,buffer2,512);
			integrator = Integrator.ar(oscillators,Rand(0.75,1.0));
			twoZero = oscillators - TwoZero.ar(oscillators,ExpRand(500.0,3000.0),Rand(0.0,pi));
			fos = oscillators >= FOS.ar(oscillators,Rand(0.1,1.0),Rand(0.1,1.0),Rand(0.1,0.5));
			decimate = DecimatorC.ar(oscillators,Rand(0.1,0.7));
			freqShift = FreqShift.ar(oscillators,Rand(-1000.0,3000.0) * modulators,Rand(0,2pi));
			freqShift = FreqShift.ar(freqShift,Rand(-3000.0,1000.0) * modulators,Rand(0,2pi));
			klank = Klank.ar(`[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],nil,[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],oscillators,ExpRand(20.0,400.0),0,Rand(0.1,2.0));
			ringMod = oscillators ring4: ball;
			divider = (PulseDivider.ar(oscillators,ExpRand(2.0,2000.0),0) * oscillators)+feed;
			effects = Select.ar(
				IRand(0,13),
				[
					verb,
					delay,
					ringz,
					filter,
					filter2,
					convolve,
					integrator,
					twoZero,
					fos,
					decimate,
					freqShift,
					klank,
					ringMod,
					divider
				]);
			signal = Limiter.ar(LeakDC.ar(Mix.new(effects))*2,0.4,0.01).softclip;
			feedEffects = Select.ar(
				IRand(0,1),
				[
					BufDelayC.ar(LocalBuf(44100*0.25),signal*Rand(0.1,0.45),Rand(0.01,0.25)),
					BufCombC.ar(LocalBuf(44100*0.25),signal*Rand(0.1,1.0),Rand(0.01,0.25),Rand(0.0001,0.25)),
					
				]);
			signal = signal*env;
			Out.ar(out,Mix.new(signal)*amp);
			LocalOut.ar(feedEffects);
		}).store;
		
		
		SynthDef.new(\MiniBatGeneratorFFT,{
			|amp=0.5,out=0,gate=1|
			var fft,signal,buffer,sine,pulse,chain,env,feed,oscillators;
			var delay,formlet,osc,delayBuf,noise,sine2,sine2Freq,formant;
			env = EnvGen.ar(Env.asr(0.0001,1.0,0.1,4),gate:gate,doneAction:2);
			buffer = LocalBuf([16384,16384,16384]);
			delayBuf = LocalBuf(44100*0.25);
			feed = LocalIn.ar(1);
			sine = SinOsc.ar((SinOsc.ar(ExpRand(1.0,1000.0),0,0.5,0.5)*ExpRand(5.0,500.0)) + (feed*ExpRand(20.0,50.0)),0,0.5) + feed;
			pulse = Pulse.ar(ExpRand(5.0,1000.0) * LFPulse.ar(ExpRand(1.0,20.0),0,Rand(0.1,0.9)),Rand(0.1,0.9) ring1: feed,0.5) + feed;
			formlet = Formlet.ar(
				Pulse.ar(ExpRand(2.0,15.0)),
				ExpRand(40.0,3000.0) + (feed*ExpRand(200,1000)),
				ExpRand(0.0001,0.1),ExpRand(0.25,0.5)) ring2: feed;
			osc = Osc.ar(delayBuf,ExpRand(0.5,2.0),0,0.5) + Decay.ar(Impulse.ar(ExpRand(5.0,15.0)),Rand(0.1,0.5),SinOsc.ar(ExpRand(20,1000.0),0,0.25));
			noise = BPF.ar(Pulse.ar(ExpRand(5000,50000),0.5)+feed,ExpRand(300.0,1000.0)+(LFNoise1.ar(Rand(1.0,5.0),0,0.5,0.5)*ExpRand(1.0,100.0)),0.3)+feed;
			sine2Freq = ExpRand(4000.0,300000.0);
			sine2 = SinOsc.ar(sine2Freq*SinOsc.ar(ExpRand(0.5,1500.0)*feed,0,0.5,0.5),0,0.05)+
				SinOsc.ar(sine2Freq+(feed*sine2Freq*ExpRand(0.1,0.25))*SinOsc.ar(ExpRand(0.15,1500.0),0,0.5,0.5),0,0.05)+feed;
			formant = Formant.ar(
				ExpRand(30.0,100.0)+(feed*ExpRand(1.0,40.0)),
				ExpRand(40.0,800.0)*SinOsc.ar(ExpRand(0.5,20.0),0,0.5,0.5),
				120+(ExpRand(20.0,1000.0)*SinOsc.ar(feed*ExpRand(0.5,80.0)))
				)+feed;
			oscillators = Select.ar(
				IRand(0,6),
				[ sine,pulse,formlet,osc,noise,sine2,formant ])*env;
			chain = FFT.new(buffer,[oscillators,oscillators,oscillators],0.5,0,1,16384);
			chain[0] = PV_MagFreeze(chain[0],LFNoise1.ar(ExpRand(0.3,1.0)));
			chain[0] = PV_Diffuser(chain[0],LFNoise1.ar(ExpRand(0.3,1.0)));
			//chain[1] = PV_BinShift(chain[1],ExpRand(0,3));
			//chain[1] = PV_RandComb(chain[1],Pulse.ar(ExpRand(0.5,10.0)),Dust.kr(ExpRand(0.5,5.0)));
			chain[1] = PV_Mul(chain[1],Decay.ar(Dust.ar(Rand(5.0,20.0)),ExpRand(0.05,0.25)));
			chain[1] = PV_PhaseShift(chain[1],Rand(0,2pi));
			chain[2] = PV_Add(chain[2],SinOsc.ar(ExpRand(3.0,200.0)*SinOsc.ar(ExpRand(0.5,80.0),0,0.5,0.5),0,0.5,0.5)*ExpRand(0.1,2pi));
			chain[2] = PV_ConformalMap(chain[2],0,LFPulse.ar(ExpRand(20.0,5000.0),0,Rand(0.1,0.4),Rand(2,5)));
			fft = IFFT(chain);
			fft = Select.ar(IRand(0,2),fft);
			signal = Limiter.ar(fft*2,0.4,0.01).softclip;
			delay = BufDelayC.ar(delayBuf,signal,Rand(0,0.25));
			Out.ar(out,signal*env*amp);
			LocalOut.ar(delay*Rand(0.1,0.45));
		}).store;
		
		
		SynthDef.new(\MiniBatGenerator2,
			{ arg gate=1.0,freq=66.6,amp=0.5,out=0,dur=0.25;
			var rand,env,dust,impulses,sins,either,slide,pulse,pure,crackle,in1,in0,blip,bass,noise,gendy,source,clean,filter,hpf;
			var lpf,ringz,onezero,twozero,hpz,formlet,filterz,constrain,signal,feed;
			rand = Rand(2.5,10);
			env = EnvGen.ar(Env.asr(0.0001,1.0,0.1,4),gate:gate,doneAction:2);
			//env = EnvGen.kr(Env.new([0,1.0,0.1,0],[dur*0.5,dur*0.5,dur],4,2,0),gate,doneAction:2);
			dust = Dust.ar(Rand(5.0,100.0),1)+Impulse.ar(3,1,1,1)+Impulse.ar(1.7,1,1,1);
			impulses =  Impulse.ar(ExpRand(0.5,20.0),0,1,1)*Impulse.ar(ExpRand(0.5,20),0.5,1,1);
			sins = SinOsc.ar(ExpRand(20.0,500.0),0.3,0.5,0.5)+SinOsc.ar(ExpRand(5.0,70.0),0.5,0.5,0.5);
			slide = Select.ar(IRand(0,1),[XLine.ar(6.66*Rand(0,3)+20,666*Rand(0,3)+0.01,Rand(0.1,5),1),XLine.ar(666*Rand(0,3)+20,6.66*Rand(0,3)+20,Rand(0,5)+1,1)]);
			pure = SinOsc.ar(ExpRand(33,6000.0),0,1*env*Pulse.ar(1.1*Rand(0,2)+0.5,0,0.5,1));
			either = Select.ar(IRand(0,3),[dust,impulses,sins,slide]).clip2(1.0);
			pulse = Pulse.ar(14*LFNoise2.ar(1.66*Rand(0,1)+1*either,1),0.5*SinOsc.kr(ExpRand(0.1,5000.0)*either+0.1,0,0.5*env).wrap2(1.0),1*env);
			blip = Blip.ar(ExpRand(20.0,66.0),Lag.ar(dust*impulses,0.5),1);
			noise = LFNoise1.ar(ExpRand(0.1,300.0)*either);
			feed = LocalIn.ar(2);
			in1 = feed[1]+(feed[0]*2);
			in0 = feed[0]+(feed[1]*2);
			bass = SinOsc.ar(ExpRand(20,80),0,0.7*env);
			crackle = Crackle.ar(Rand(0.9,2.1),1);
			gendy = Gendy1.ar(1,1,1.0,1.0, Lag.ar(impulses.abs,0.2),Lag.ar(impulses.abs,0.2),0.5,0.5,12,12,1);
			source = Select.ar(
				IRand(0,15),
				[gendy,gendy,gendy,pulse,pulse,pulse,crackle,noise,pure,bass,either+bass,either+pulse,either+noise,in0+pure,crackle,crackle]);
			source = source + Select.ar(
				IRand(0,20),
				[blip,blip,pulse,pulse,pulse,noise,pure,in0-pulse,bass,in0+bass,blip,in0+noise,pure-in0,crackle,crackle,either,either,either,either-in0,either,either]);
			source = Limiter.ar(source,0.95,0.01);
			source = LeakDC.ar(source);
			filter = BPF.ar(source,ExpRand(40.0,5000.0)*LFNoise2.ar(ExpRand(0.1,20.0)*either,0.5,0.5),0.1,1*env);
			lpf = RLPF.ar(source,ExpRand(100.0,5000.0)*Pulse.ar(ExpRand(0.5,20.0),Rand(0.1,0.9),0.5,0.5)*either,0.02,1);
			hpf = RHPF.ar(source,ExpRand(33,666)*Pulse.ar(ExpRand(0.5,20.0),Rand(0.1,0.9),0.5,0.5)*either,0.02,1);
			ringz = Ringz.ar(source,ExpRand(80.0,1000.0)*either,Rand(0.1,5.0));
			clean = source;
			onezero = OneZero.ar(source,either.wrap2(0.5),1);
			hpz = HPZ1.ar(source,1);
			twozero = TwoZero.ar(source,ExpRand(0,6666)+33.3,either.wrap2(1.0),1);
			formlet = Formlet.ar(source,either,1,ExpRand(0.1,10.0));
			filterz = Select.ar(IRand(0,8),[filter,lpf,ringz,clean,hpf,onezero,twozero,hpz,formlet]);
			filterz = Select.ar(IRand(0,2),[(filterz).wrap2(Rand(0.1,1)),(filterz).clip2(Rand(0.1,1)),(filterz).fold2(Rand(0.1,1))]);
			constrain = Limiter.ar(filterz*2,0.4,0.01).softclip;
			signal = LeakDC.ar(constrain,0.995,1);
			Out.ar(out, Mix.new(signal)*amp);
			LocalOut.ar(DelayC.ar(signal,1.0,0.4,1));
		}).store;

			
	}
}